package com.blog4j.user.service.impl;

import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.core.collection.CollectionUtil;
import com.alibaba.excel.EasyExcel;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.blog4j.api.client.FeignArticle;
import com.blog4j.api.client.FeignSystem;
import com.blog4j.api.vo.MessageVo;
import com.blog4j.api.vo.OrganizationVo;
import com.blog4j.api.vo.SystemBaseConfigVo;
import com.blog4j.api.vo.UserIllegalRecordVo;
import com.blog4j.api.vo.UserInfoVo;
import com.blog4j.common.constants.CacheConstants;
import com.blog4j.common.constants.CommonConstant;
import com.blog4j.common.enums.ErrorEnum;
import com.blog4j.common.enums.RoleEnum;
import com.blog4j.common.enums.UserIllegalTypeEnum;
import com.blog4j.common.enums.UserSexEnum;
import com.blog4j.common.enums.UserStatusEnum;
import com.blog4j.common.enums.YesOrNoEnum;
import com.blog4j.common.exception.Blog4jException;
import com.blog4j.common.utils.CommonUtil;
import com.blog4j.common.utils.ExcelUtil;
import com.blog4j.common.utils.IdGeneratorSnowflakeUtil;
import com.blog4j.common.utils.RedisUtil;
import com.blog4j.common.utils.RsaUtil;
import com.blog4j.common.utils.ValidateUtil;
import com.blog4j.api.vo.DeleteUserArticleVo;
import com.blog4j.user.component.AsyncService;
import com.blog4j.user.entity.OrganizationEntity;
import com.blog4j.user.entity.OrganizationUserRelEntity;
import com.blog4j.user.entity.RoleEntity;
import com.blog4j.user.entity.UserEntity;
import com.blog4j.user.entity.UserUpdatePwdTimesEntity;
import com.blog4j.user.listener.ImportUserExcelListener;
import com.blog4j.user.mapper.OrganizationMapper;
import com.blog4j.user.mapper.OrganizationUserRelMapper;
import com.blog4j.user.mapper.RoleMapper;
import com.blog4j.user.mapper.UserMapper;
import com.blog4j.user.mapper.UserUpdatePwdTimesMapper;
import com.blog4j.user.model.UserExcel;
import com.blog4j.user.service.UserIllegalRecordService;
import com.blog4j.user.service.UserService;
import com.blog4j.user.utils.UserUtil;
import com.blog4j.user.vo.req.BatchCreateUserReqVo;
import com.blog4j.user.vo.req.CreateUserReqVo;
import com.blog4j.user.vo.req.DeleteUserReqVo;
import com.blog4j.api.vo.EditUserLastLoginTimeReqVo;
import com.blog4j.user.vo.req.EditUserBaseInfoReqVo;
import com.blog4j.user.vo.req.EditUserReqVo;
import com.blog4j.user.vo.req.ExportUserReqVo;
import com.blog4j.user.vo.req.RegisterReqVo;
import com.blog4j.user.vo.req.UpdateUserPwdReqVo;
import com.blog4j.user.vo.req.UserListReqVo;
import com.blog4j.user.vo.req.ValidEmailReqVo;
import com.blog4j.user.vo.req.ValidPhoneReqVo;
import com.blog4j.user.vo.resp.UserInfoRespVo;
import com.blog4j.user.vo.resp.UserListRespVo;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import lombok.RequiredArgsConstructor;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Files;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * @author 98k灬
 * @version v1.0.0
 * @Description : 功能描述
 * @Create on : 2024/6/22 13:16
 **/
@Service
@RequiredArgsConstructor(onConstructor_ = @Autowired)
public class UserServiceImpl extends ServiceImpl<UserMapper, UserEntity> implements UserService {
    private final RoleMapper roleMapper;
    private final OrganizationUserRelMapper organizationUserRelMapper;
    private final FeignArticle feignArticle;
    private final ExcelUtil excelUtil;
    private final UserMapper userMapper;
    private final FeignSystem feignSystem;
    private final RedisUtil redisUtil;
    private final ObjectMapper objectMapper;
    private final UserUtil userUtil;
    private final OrganizationMapper organizationMapper;
    private final AsyncService asyncService;
    private final UserUpdatePwdTimesMapper userUpdatePwdTimesMapper;
    private final UserIllegalRecordService userIllegalRecordService;

    /**
     * 根据用户名获取用户信息
     *
     * @param userName 用户名
     * @return 用户信息
     */
    @Override
    public UserInfoVo getUserInfoByUserName(String userName) {
        if (StringUtils.isBlank(userName)) {
            log.error("UserName is blank .");
            throw new Blog4jException(ErrorEnum.INVALID_PARAMETER_ERROR);
        }
        LambdaQueryWrapper<UserEntity> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(UserEntity::getUserName, userName);
        UserEntity userEntity = this.baseMapper.selectOne(wrapper);
        if (Objects.isNull(userEntity)) {
            log.error("User is empty .");
            throw new Blog4jException(ErrorEnum.USER_NOT_EXIST_ERROR);
        }
        RoleEntity roleEntity = roleMapper.selectById(userEntity.getRoleId());
        UserInfoVo userInfoVo = new UserInfoVo();
        BeanUtils.copyProperties(userEntity, userInfoVo);
        userInfoVo.setRoleCode(roleEntity.getRoleCode())
                .setRoleName(roleEntity.getRoleName())
                .setRoleId(userEntity.getRoleId());
        return userInfoVo;
    }

    /**
     * 根据用户ID获取用户信息
     *
     * @param userId 用户ID
     * @return 用户信息
     */
    @Override
    public UserInfoVo getUserInfoByUserId(String userId) {
        if (StringUtils.isBlank(userId)) {
            log.error("userId is blank .");
            throw new Blog4jException(ErrorEnum.INVALID_PARAMETER_ERROR);
        }
        LambdaQueryWrapper<UserEntity> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(UserEntity::getUserId, userId);
        queryWrapper.ne(UserEntity::getStatus, UserStatusEnum.LOCK.getCode());
        UserEntity userEntity = this.baseMapper.selectOne(queryWrapper);
        if (Objects.isNull(userEntity)) {
            log.error("User is empty .");
            throw new Blog4jException(ErrorEnum.USER_NOT_EXIST_ERROR);
        }

        RoleEntity roleEntity = roleMapper.selectById(userEntity.getRoleId());
        UserInfoVo userInfoVo = new UserInfoVo();
        BeanUtils.copyProperties(userEntity, userInfoVo);
        userInfoVo.setRoleCode(roleEntity.getRoleCode())
                .setRoleName(roleEntity.getRoleName())
                .setRoleId(userEntity.getRoleId());

        LambdaQueryWrapper<OrganizationUserRelEntity> wrapper = new LambdaQueryWrapper<OrganizationUserRelEntity>()
                .eq(OrganizationUserRelEntity::getUserId, userId);
        List<OrganizationUserRelEntity> organizationUserRelList = organizationUserRelMapper.selectList(wrapper);
        if (CollectionUtil.isNotEmpty(organizationUserRelList)) {
            List<String> organizationIdList = organizationUserRelList.stream()
                    .map(OrganizationUserRelEntity::getOrganizationId).collect(Collectors.toList());
            List<OrganizationEntity> organizationList = organizationMapper.selectBatchIds(organizationIdList);
            List<OrganizationVo> organizationVos = organizationList.stream().map(item -> {
                OrganizationVo organizationVo = new OrganizationVo();
                BeanUtils.copyProperties(item, organizationVo);
                return organizationVo;
            }).collect(Collectors.toList());
            userInfoVo.setOrganizationList(organizationVos);
        }

        return userInfoVo;
    }

    /**
     * 查询用户列表
     *
     * @param reqVo 查询条件
     * @return 用户列表
     */
    @Override
    public PageInfo<UserListRespVo> userList(UserListReqVo reqVo) {
        Integer pageNo = reqVo.getPageNo();
        Integer pageSize = reqVo.getPageSize();
        if (pageSize > CommonConstant.MAX_PAGE_SIZE) {
            pageSize = CommonConstant.MAX_PAGE_SIZE;
        }
        Integer status = reqVo.getStatus();
        String userName = reqVo.getUserName();


        LambdaQueryWrapper<UserEntity> wrapper = new LambdaQueryWrapper<>();
        wrapper.orderByDesc(UserEntity::getCreateTime);
        if (Objects.nonNull(status)) {
            wrapper.eq(UserEntity::getStatus, status);
        }
        if (StringUtils.isNotBlank(userName)) {
            wrapper.like(UserEntity::getUserName, userName);
        }
        Page<Object> page = PageHelper.startPage(pageNo, pageSize);
        List<UserEntity> userList = this.baseMapper.selectList(wrapper);
        if (CollectionUtil.isEmpty(userList)) {
            return new PageInfo<>(new ArrayList<>());
        }

        List<UserListRespVo> userListRespVoList = userList.stream().map(item -> {
            UserListRespVo userListRespVo = new UserListRespVo();
            BeanUtils.copyProperties(item, userListRespVo);
            return userListRespVo;
        }).collect(Collectors.toList());

        List<String> roleIds = userListRespVoList.stream().map(UserListRespVo::getRoleId).collect(Collectors.toList());
        List<RoleEntity> roleList = roleMapper.selectBatchIds(roleIds);
        for (UserListRespVo userListRespVo : userListRespVoList) {
            List<RoleEntity> list = roleList.stream()
                    .filter(item -> StringUtils.equals(userListRespVo.getRoleId(), item.getRoleId())).collect(Collectors.toList());
            if (CollectionUtil.isNotEmpty(list)) {
                RoleEntity role = list.get(0);
                userListRespVo.setRoleId(role.getRoleId()).setRoleName(role.getRoleName());
            }
        }

        PageInfo<UserListRespVo> pageInfo = new PageInfo<>(userListRespVoList);
        pageInfo.setTotal(page.getTotal());
        return pageInfo;
    }

    /**
     * 查询组织用户
     *
     * @param reqVo 查询条件
     * @return 组织用户
     */
    @Override
    public List<UserListRespVo> organizationUserList(UserListReqVo reqVo) {
        if (StringUtils.isBlank(reqVo.getOrganizationId())) {
            throw new Blog4jException(ErrorEnum.INVALID_PARAMETER_ERROR);
        }
        PageHelper.startPage(reqVo.getPageNo(), reqVo.getPageSize());
        return this.baseMapper.userList(reqVo.getUserName(), reqVo.getStatus(), reqVo.getOrganizationId());
    }

    /**
     * 创建用户信息
     *
     * @param reqVo 用户信息
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public void create(CreateUserReqVo reqVo) {
        this.baseMapper.insert(this.createUser(reqVo));
    }

    private synchronized UserEntity createUser(CreateUserReqVo reqVo) {
        this.beforeCreate(reqVo);
        UserEntity user = new UserEntity();
        BeanUtils.copyProperties(reqVo, user);
        String userId = IdGeneratorSnowflakeUtil.snowflakeId();
        SystemBaseConfigVo systemBaseConfig = this.getSystemBaseConfig();
        user.setUserId(userId)
                .setId(userUtil.getUserSize() + 1)
                .setUpdateTime(CommonUtil.getCurrentDateTime())
                .setCreateTime(CommonUtil.getCurrentDateTime())
                .setPassword(RsaUtil.encrypt(systemBaseConfig.getInitPassword()))
                .setDeleted(YesOrNoEnum.NO.getCode())
                .setShowFansList(YesOrNoEnum.YES.getCode())
                .setShowCategoryList(YesOrNoEnum.YES.getCode())
                .setShowFavoriteList(YesOrNoEnum.YES.getCode())
                .setStatus(UserStatusEnum.NORMAL.getCode());
        if (StringUtils.isBlank(reqVo.getRoleId())) {
            LambdaQueryWrapper<RoleEntity> wrapper = new LambdaQueryWrapper<RoleEntity>()
                    .eq(RoleEntity::getRoleCode, RoleEnum.ORDINARY.getDesc());
            RoleEntity role = roleMapper.selectOne(wrapper);
            if (Objects.isNull(role)) {
                throw new Blog4jException(ErrorEnum.SYSTEM_ERROR);
            }
            user.setRoleId(role.getRoleId());
        }

        if (StringUtils.isBlank(reqVo.getAvatar())) {
            user.setAvatar(systemBaseConfig.getUserDefaultAvatar());
        }

        if (!userUtil.checkUserName(reqVo.getUserName(), userId)) {
            addUserIllegalRecord(userId, UserIllegalTypeEnum.ILLEGAL_USER_NAME.getType());
            throw new Blog4jException(ErrorEnum.USER_NAME_VERIFY_REJECT_ERROR);
        }

        if (StringUtils.isNotBlank(reqVo.getSign()) && !userUtil.checkUserSign(reqVo.getSign(), userId)) {
            addUserIllegalRecord(userId, UserIllegalTypeEnum.ILLEGAL_USER_SIGN.getType());
            throw new Blog4jException(ErrorEnum.USER_SIGN_ILLEGAL_ERROR);
        }

        return user;
    }



    /**
     * 编辑用户信息
     *
     * @param reqVo 用户信息
     */
    @Override
    public void edit(EditUserReqVo reqVo) {
        UserEntity user = this.beforeUpdate(reqVo);
        BeanUtils.copyProperties(reqVo, user);
        user.setUpdateTime(CommonUtil.getCurrentDateTime());
        this.baseMapper.updateById(user);
    }

    /**
     * 删除用户
     *
     * @param reqVo 用户信息
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public void delete(DeleteUserReqVo reqVo) {
        this.beforeDelete(reqVo);
        // 删除用户名下的文章
        this.deleteUserArticle(reqVo);
        // 删除用户的组织关系
        this.deleteOrganizationRel(reqVo);
        this.baseMapper.deleteBatchIds(reqVo.getUserIds());
    }

    /**
     * 更新用户的最近一次登录时间
     *
     * @param reqVo 请求信息
     */
    @Override
    public void updateUserLastLoginTime(EditUserLastLoginTimeReqVo reqVo) {
        String userId = reqVo.getUserId();
        String lastLoginTime = reqVo.getLastLoginTime();
        UserEntity user = this.baseMapper.selectById(userId);
        if (Objects.isNull(user)) {
            throw new Blog4jException(ErrorEnum.USER_NOT_EXIST_ERROR);
        }
        user.setLastLoginTime(lastLoginTime);
        this.baseMapper.updateById(user);
    }

    /**
     * 用户批量导入
     *
     * @param multipartFile 文件
     * @return 解析之后的用户信息
     */
    @Override
    public List<UserExcel> importUser(MultipartFile multipartFile) {
        List<UserExcel> dataList = new ArrayList<>();
        try {
            File file = CommonUtil.convertMultipartFileToFile(multipartFile);
            InputStream inputStream = Files.newInputStream(file.toPath());
            dataList = EasyExcel.read(inputStream, UserExcel.class, new ImportUserExcelListener(dataList, userMapper))
                    .headRowNumber(1)
                    .sheet(0)
                    .doReadSync();
        } catch (IOException ioException) {
            throw new Blog4jException(ErrorEnum.IO_ERROR);
        }
        return dataList;
    }

    /**
     * 批量创建用户信息
     *
     * @param reqVo 用户信息
     */
    @Override
    public void batchCreate(BatchCreateUserReqVo reqVo) {
        List<CreateUserReqVo> list = reqVo.getList();
        List<UserEntity> userList = list.stream().map(item -> {
            CreateUserReqVo userReqVo = new CreateUserReqVo();
            BeanUtils.copyProperties(item, userReqVo);
            return this.createUser(userReqVo);
        }).collect(Collectors.toList());
        this.baseMapper.batchInsert(userList);
    }

    /**
     * 用户导出
     *
     * @param exportUserReqVo 用户ID
     */
    @Override
    public void exportUser(ExportUserReqVo exportUserReqVo, HttpServletResponse response) {
        List<UserEntity> userList = this.baseMapper.selectBatchIds(exportUserReqVo.getUserIds());
        if (CollectionUtil.isEmpty(userList)) {
            throw new Blog4jException(ErrorEnum.INVALID_PARAMETER_ERROR);
        }

        List<UserExcel> userExcelList = userList.stream().map(item -> {
            UserExcel userExcel = new UserExcel();
            BeanUtils.copyProperties(item, userExcel);
            return userExcel;
        }).collect(Collectors.toList());
        String path = excelUtil.export(userExcelList, UserExcel.class, "用户信息");
        try {
            ExcelUtil.exportExcel(response, path);
        } catch (Exception exception) {
            throw new Blog4jException(ErrorEnum.EXPORT_USER_ERROR);
        }
    }

    /**
     * 根据手机号码查询用户信息
     *
     * @param phone 手机号码
     * @return 用户信息
     */
    @Override
    public UserInfoVo getUserInfoByPhone(String phone) {
        LambdaQueryWrapper<UserEntity> wrapper = new LambdaQueryWrapper<UserEntity>()
                .eq(UserEntity::getPhone, phone);
        UserEntity user = this.baseMapper.selectOne(wrapper);
        if (Objects.isNull(user)) {
            throw new Blog4jException(ErrorEnum.USER_NOT_EXIST_ERROR);
        }
        UserInfoVo userInfoVo = new UserInfoVo();
        BeanUtils.copyProperties(user, userInfoVo);

        RoleEntity roleEntity = roleMapper.selectById(user.getRoleId());
        BeanUtils.copyProperties(user, userInfoVo);
        userInfoVo.setRoleCode(roleEntity.getRoleCode())
                .setRoleName(roleEntity.getRoleName())
                .setRoleId(user.getRoleId());
        return userInfoVo;
    }

    /**
     * 根据用户的映射ID获取用户信息
     *
     * @param id 用户的映射ID
     * @return 用户信息
     */
    @Override
    public UserInfoVo getUserInfoById(Integer id) {
        LambdaQueryWrapper<UserEntity> wrapper = new LambdaQueryWrapper<UserEntity>()
                .eq(UserEntity::getStatus, UserStatusEnum.NORMAL.getCode())
                .eq(UserEntity::getId, id);
        UserEntity user = this.baseMapper.selectOne(wrapper);
        if (Objects.isNull(user)) {
            throw new Blog4jException(ErrorEnum.USER_NOT_EXIST_ERROR);
        }

        UserInfoVo userInfoVo = new UserInfoVo();
        BeanUtils.copyProperties(user, userInfoVo);
        return userInfoVo;
    }

    /**
     * 用户注册
     *
     * @param reqVo 注册信息
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public void register(RegisterReqVo reqVo) {
        String password = reqVo.getPassword();
        String userName = reqVo.getUserName();

        LambdaQueryWrapper<UserEntity> wrapper = new LambdaQueryWrapper<UserEntity>()
                .eq(UserEntity::getUserName, userName);
        UserEntity userEntity = this.baseMapper.selectOne(wrapper);
        if (Objects.nonNull(userEntity)) {
            throw new Blog4jException(ErrorEnum.USERNAME_REPEAT_ERROR);
        }

        LambdaQueryWrapper<RoleEntity> wrapper1 = new LambdaQueryWrapper<RoleEntity>()
                .eq(RoleEntity::getRoleCode, RoleEnum.ORDINARY.getDesc());
        RoleEntity role = roleMapper.selectOne(wrapper1);
        if (Objects.isNull(role)) {
            throw new Blog4jException(ErrorEnum.SYSTEM_ERROR);
        }

        SystemBaseConfigVo systemBaseConfig = getSystemBaseConfig();
        String userId = IdGeneratorSnowflakeUtil.snowflakeId();
        UserEntity user = UserEntity.builder()
                .userId(userId)
                .roleId(role.getRoleId())
                .userName(userName)
                .password(RsaUtil.encrypt(password))
                .status(UserStatusEnum.NORMAL.getCode())
                .deleted(YesOrNoEnum.NO.getCode())
                .id(userUtil.getUserSize() + 1)
                .avatar(systemBaseConfig.getUserDefaultAvatar())
                .homepageCover(systemBaseConfig.getUserDefaultHomepage())
                .updateTime(CommonUtil.getCurrentDateTime())
                .createTime(CommonUtil.getCurrentDateTime())
                .build();
        this.baseMapper.insert(user);

        if (!userUtil.checkUserName(userName, userId)) {
            throw new Blog4jException(ErrorEnum.USER_NAME_VERIFY_REJECT_ERROR);
        }

        // 注册成功，给用户发送系统消息
        MessageVo messageVo = MessageVo.builder()
                .toUserId(user.getUserId())
                .fromUserId(userUtil.getSuperAdminUserId())
                .messageContent(CommonConstant.REGISTER_MESSAGE)
                .build();
        asyncService.sendMessage(messageVo);
    }

    /**
     * 用户个数
     *
     * @return 用户个数
     */
    @Override
    public Integer userCount() {
        return this.baseMapper.selectCount(null);
    }

    /**
     * 手机号码验证
     *
     * @param reqVo 请求
     */
    @Override
    public void validPhone(ValidPhoneReqVo reqVo) {
        String phone = reqVo.getPhone();
        String code = reqVo.getCode();

        Object cacheVal = redisUtil.get(CacheConstants.VALID_PHONE_CODE_KEY + phone);
        if (Objects.isNull(cacheVal)) {
            throw new Blog4jException(ErrorEnum.CODE_EXPIRE_ERROR);
        }

        if (!StringUtils.equals(code, (String)cacheVal)) {
            throw new Blog4jException(ErrorEnum.INVALID_CAPTCHA_ERROR);
        }

        redisUtil.del(CacheConstants.VALID_PHONE_CODE_KEY + phone);
    }

    /**
     * 编辑用户基本信息
     *
     * @param reqVo 请求
     */
    @Override
    public void editUserBaseInfo(EditUserBaseInfoReqVo reqVo) {
        String userId = reqVo.getUserId();
        String userName = reqVo.getUserName();
        String address = reqVo.getAddress();
        String email = reqVo.getEmail();
        String phone = reqVo.getPhone();

        UserEntity user = this.baseMapper.selectById(userId);
        if (Objects.isNull(user)) {
            throw new Blog4jException(ErrorEnum.USER_NOT_EXIST_ERROR);
        }

        if (StringUtils.isNotBlank(phone)) {
            LambdaQueryWrapper<UserEntity> wrapper = new LambdaQueryWrapper<UserEntity>()
                    .eq(UserEntity::getPhone, phone)
                    .ne(UserEntity::getUserId, userId);
            if (this.baseMapper.selectCount(wrapper) > 0) {
                throw new Blog4jException(ErrorEnum.PHONE_REPEAT_ERROR);
            }
        }

        LambdaQueryWrapper<UserEntity> wrapper1 = new LambdaQueryWrapper<UserEntity>()
                .eq(UserEntity::getUserName, userName)
                .ne(UserEntity::getUserId, userId);
        if (this.baseMapper.selectCount(wrapper1) > 0) {
            throw new Blog4jException(ErrorEnum.USERNAME_REPEAT_ERROR);
        }

        user.setPhone(phone)
                .setEmail(email)
                .setAddress(address)
                .setUserName(userName)
                .setSign(reqVo.getSign())
                .setUpdateTime(CommonUtil.getCurrentDateTime());
        this.baseMapper.updateById(user);
    }

    /**
     * 邮箱验证
     *
     * @param reqVo 请求
     */
    @Override
    public void validEmail(ValidEmailReqVo reqVo) {
        String email = reqVo.getEmail();
        String code = reqVo.getCode();

        Object cacheVal = redisUtil.get(CacheConstants.EMAIL_CODE_KEY + email);
        if (Objects.isNull(cacheVal)) {
            throw new Blog4jException(ErrorEnum.CODE_EXPIRE_ERROR);
        }

        if (!StringUtils.equals(code, (String)cacheVal)) {
            throw new Blog4jException(ErrorEnum.INVALID_CAPTCHA_ERROR);
        }

        redisUtil.del(CacheConstants.EMAIL_CODE_KEY + email);
    }

    /**
     * 更新用户密码
     *
     * @param reqVo 请求信息
     */
    @Override
    public void updateUserPwd(UpdateUserPwdReqVo reqVo) {
        String userId = reqVo.getUserId();
        String newPwd = reqVo.getNewPwd();
        String oldPwd = reqVo.getOldPwd();

        this.checkBeforeUpdatePwd(userId);

        LambdaQueryWrapper<UserEntity> wrapper = new LambdaQueryWrapper<UserEntity>()
                .eq(UserEntity::getUserId, userId)
                .eq(UserEntity::getStatus, UserStatusEnum.NORMAL.getCode());
        UserEntity user = this.baseMapper.selectOne(wrapper);
        if (Objects.isNull(user)) {
            throw new Blog4jException(ErrorEnum.USER_NOT_EXIST_ERROR);
        }

        if (!StringUtils.equals(RsaUtil.decrypt(user.getPassword()), oldPwd)) {
            throw new Blog4jException(ErrorEnum.OLD_PWD_ERROR);
        }

        user.setPassword(RsaUtil.encrypt(newPwd)).setUpdateTime(CommonUtil.getCurrentDateTime());
        this.updateById(user);
    }

    private void checkBeforeUpdatePwd(String userId) {
        SimpleDateFormat sdf = new SimpleDateFormat(CommonConstant.MONTH_FORMAT);
        String monthFormat = sdf.format(new Date());

        // 先删除非本月的记录
        LambdaQueryWrapper<UserUpdatePwdTimesEntity> queryWrapper = new LambdaQueryWrapper<UserUpdatePwdTimesEntity>()
                .eq(UserUpdatePwdTimesEntity::getUserId, userId)
                .ne(UserUpdatePwdTimesEntity::getDate, monthFormat);
        userUpdatePwdTimesMapper.delete(queryWrapper);

        LambdaQueryWrapper<UserUpdatePwdTimesEntity> wrapper = new LambdaQueryWrapper<UserUpdatePwdTimesEntity>()
                .eq(UserUpdatePwdTimesEntity::getUserId, userId)
                .eq(UserUpdatePwdTimesEntity::getDate, monthFormat);
        UserUpdatePwdTimesEntity userUpdatePwdTimes = userUpdatePwdTimesMapper.selectOne(wrapper);
        if (Objects.isNull(userUpdatePwdTimes)) {
            UserUpdatePwdTimesEntity userUpdatePwdTimesEntity = UserUpdatePwdTimesEntity.builder()
                    .userId(userId)
                    .times(1)
                    .date(monthFormat)
                    .build();
            userUpdatePwdTimesMapper.insert(userUpdatePwdTimesEntity);
            return;
        }
        Integer currentTimes = userUpdatePwdTimes.getTimes();
        SystemBaseConfigVo baseConfig = getSystemBaseConfig();
        if (baseConfig.getUserMonthUpdatePwdTimes() <= currentTimes) {
            throw new Blog4jException(ErrorEnum.MONTH_UPDATE_PWD_TIMES_MAX_ERROR);
        }
        currentTimes += 1;
        userUpdatePwdTimes.setTimes(currentTimes);
        userUpdatePwdTimesMapper.updateById(userUpdatePwdTimes);
    }

    /**
     * 根据用户ID获取用户信息
     *
     * @param userId 用户ID
     * @return 用户信息
     */
    @Override
    public UserInfoRespVo userInfo(String userId) {
        UserEntity user = this.baseMapper.selectById(userId);
        if (Objects.isNull(user)) {
            throw new Blog4jException(ErrorEnum.USER_NOT_EXIST_ERROR);
        }

        if (Objects.equals(UserStatusEnum.LOCK.getCode(), user.getStatus())) {
            throw new Blog4jException(ErrorEnum.USER_LOCK_ERROR);
        }
        RoleEntity roleEntity = roleMapper.selectById(user.getRoleId());
        UserInfoRespVo respVo = new UserInfoRespVo();
        BeanUtils.copyProperties(user, respVo);
        respVo.setRoleName(roleEntity.getRoleName());
        return respVo;
    }

    /**
     * 获取超级管理员信息
     *
     * @return 超级管理员信息
     */
    @Override
    public UserInfoVo getSuperAdminInfo() {
        String superAdminUserId = userUtil.getSuperAdminUserId();
        UserEntity user = this.baseMapper.selectById(superAdminUserId);
        UserInfoVo userInfoVo = new UserInfoVo();
        BeanUtils.copyProperties(user, userInfoVo);
        return userInfoVo;
    }

    /**
     * 发送消息
     *
     * @param messageVo 消息
     */
    @Override
    public void sendMessage(MessageVo messageVo) {
        asyncService.sendMessage(messageVo);
    }

    // -----------------------------------private---------------------------------------------------------

    private void deleteUserArticle(DeleteUserReqVo reqVo) {
        List<String> userIds = reqVo.getUserIds();
        feignArticle.deleteUserArticle(DeleteUserArticleVo.builder().userIds(userIds).build());
    }

    private void deleteOrganizationRel(DeleteUserReqVo reqVo) {
        List<String> userIds = reqVo.getUserIds();
        LambdaQueryWrapper<OrganizationUserRelEntity> wrapper = new LambdaQueryWrapper<OrganizationUserRelEntity>()
                .in(OrganizationUserRelEntity::getUserId, userIds);
        List<OrganizationUserRelEntity> organizationUserRelList
                = organizationUserRelMapper.selectList(wrapper);
        if (CollectionUtil.isEmpty(organizationUserRelList)) {
            return;
        }

        Set<Integer> ids = organizationUserRelList.stream()
                .map(OrganizationUserRelEntity::getId).collect(Collectors.toSet());
        organizationUserRelMapper.deleteBatchIds(ids);
    }

    private void beforeDelete(DeleteUserReqVo reqVo) {
        String currentLoginUserId = StpUtil.getLoginIdAsString();
        List<String> userIds = reqVo.getUserIds();
        if (userIds.contains(currentLoginUserId)) {
            throw new Blog4jException(ErrorEnum.DELETE_CURRENT_LOGIN_ERROR);
        }

        List<UserEntity> userList = this.baseMapper.selectBatchIds(userIds);
        if (CollectionUtil.size(userList) != CollectionUtil.size(userIds)) {
            throw new Blog4jException(ErrorEnum.USER_NOT_EXIST_ERROR);
        }

        // 不能删除超级管理员和组织管理员
        Set<String> roleIdSet = userList.stream().map(UserEntity::getRoleId).collect(Collectors.toSet());
        List<RoleEntity> roleList = roleMapper.selectBatchIds(roleIdSet);
        if (CollectionUtil.isNotEmpty(roleList)) {
            List<RoleEntity> list = roleList.stream().filter(role -> StringUtils.equals(role.getRoleCode(), RoleEnum.ORGANIZATION_ADMIN.getDesc()) ||
                    StringUtils.equals(role.getRoleCode(), RoleEnum.SUPER_ADMIN.getDesc())).collect(Collectors.toList());
            if (CollectionUtil.isNotEmpty(list)) {
                throw new Blog4jException(ErrorEnum.DELETE_ORGANIZATION_ADMIN_ERROR);
            }
        }
    }

    private UserEntity beforeUpdate(EditUserReqVo reqVo) {
        // 用户ID是否存在
        String userId = reqVo.getUserId();
        UserEntity user = this.baseMapper.selectById(userId);
        if (Objects.isNull(user)) {
            throw new Blog4jException(ErrorEnum.USER_NOT_EXIST_ERROR);
        }

        if (!StringUtils.equals(reqVo.getUserName(), user.getUserName())
                && !userUtil.checkUserName(reqVo.getUserName(), userId)) {
            addUserIllegalRecord(userId, UserIllegalTypeEnum.ILLEGAL_USER_NAME.getType());
            throw new Blog4jException(ErrorEnum.USER_NAME_VERIFY_REJECT_ERROR);
        }

        if (!StringUtils.equals(reqVo.getSign(), user.getSign())
                && !userUtil.checkUserSign(reqVo.getSign(), userId)) {
            addUserIllegalRecord(userId, UserIllegalTypeEnum.ILLEGAL_USER_SIGN.getType());
            throw new Blog4jException(ErrorEnum.USER_SIGN_ILLEGAL_ERROR);
        }

        // 用户名称不能重复
        LambdaQueryWrapper<UserEntity> wrapper1 = new LambdaQueryWrapper<UserEntity>()
                .eq(UserEntity::getUserName, reqVo.getUserName())
                .ne(UserEntity::getUserId, userId);
        UserEntity val1 = this.baseMapper.selectOne(wrapper1);
        if (Objects.nonNull(val1)) {
            throw new Blog4jException(ErrorEnum.USERNAME_REPEAT_ERROR);
        }

        // 用户手机号码不能重复
        if (StringUtils.isNotBlank(reqVo.getPhone())) {
            LambdaQueryWrapper<UserEntity> wrapper2 = new LambdaQueryWrapper<UserEntity>()
                    .eq(UserEntity::getPhone, reqVo.getPhone())
                    .ne(UserEntity::getUserId, userId);
            UserEntity val2 = this.baseMapper.selectOne(wrapper2);
            if (Objects.nonNull(val2)) {
                throw new Blog4jException(ErrorEnum.PHONE_REPEAT_ERROR);
            }
        }

        // 角色是否合法
        if (StringUtils.isNotBlank(reqVo.getRoleId())) {
            RoleEntity role = roleMapper.selectById(reqVo.getRoleId());
            if (Objects.isNull(role)) {
                throw new Blog4jException(ErrorEnum.ROLE_INFO_EMPTY_ERROR);
            }
        }

        if (StringUtils.isNotBlank(reqVo.getPhone()) && !ValidateUtil.isValidMobile(reqVo.getPhone())) {
            throw new Blog4jException(ErrorEnum.PHONE_ERROR);
        }

        Integer sex = reqVo.getSex();
        if (Objects.nonNull(sex)) {
            if (!Objects.equals(sex, UserSexEnum.MAN.getCode()) &&
                    !Objects.equals(sex, UserSexEnum.WOMAN.getCode()) &&
                    !Objects.equals(sex, UserSexEnum.SECRET.getCode())) {
                throw new Blog4jException(ErrorEnum.SEX_ERROR);
            }
        }

        return user;
    }

    private void beforeCreate(CreateUserReqVo reqVo) {
        // 用户名称不能重复
        LambdaQueryWrapper<UserEntity> wrapper1 = new LambdaQueryWrapper<UserEntity>().eq(UserEntity::getUserName, reqVo.getUserName());
        List<UserEntity> val1 = this.baseMapper.selectList(wrapper1);
        if (CollectionUtil.isNotEmpty(val1)) {
            throw new Blog4jException(ErrorEnum.USERNAME_REPEAT_ERROR);
        }

        // 用户手机号码不能重复
        if (StringUtils.isNotBlank(reqVo.getPhone())) {
            LambdaQueryWrapper<UserEntity> wrapper2 = new LambdaQueryWrapper<UserEntity>().eq(UserEntity::getPhone, reqVo.getPhone());
            List<UserEntity> val2 = this.baseMapper.selectList(wrapper2);
            if (CollectionUtil.isNotEmpty(val2)) {
                throw new Blog4jException(ErrorEnum.PHONE_REPEAT_ERROR);
            }
        }

        // 角色是否合法
        if (StringUtils.isNotBlank(reqVo.getRoleId())) {
            RoleEntity role = roleMapper.selectById(reqVo.getRoleId());
            if (Objects.isNull(role)) {
                throw new Blog4jException(ErrorEnum.ROLE_INFO_EMPTY_ERROR);
            }
        }

        if (StringUtils.isNotBlank(reqVo.getPhone()) && !ValidateUtil.isValidMobile(reqVo.getPhone())) {
            throw new Blog4jException(ErrorEnum.PHONE_ERROR);
        }

        Integer sex = reqVo.getSex();
        if (Objects.nonNull(sex)) {
            if (!Objects.equals(sex, UserSexEnum.MAN.getCode()) &&
                    !Objects.equals(sex, UserSexEnum.WOMAN.getCode()) &&
                    !Objects.equals(sex, UserSexEnum.SECRET.getCode())) {
                throw new Blog4jException(ErrorEnum.SEX_ERROR);
            }
        }
    }

    private SystemBaseConfigVo getSystemBaseConfig()  {
        Object val = redisUtil.get(CacheConstants.SYSTEM_BASE_CONFIG_KEY);
        if (Objects.isNull(val)) {
            return feignSystem.getBaseSystemConfig();
        }

        try {
            JSONArray jsonArray = JSON.parseArray((String) val);
            JSONObject jsonObject = JSON.parseObject(objectMapper.writeValueAsString(jsonArray.get(1)));
            return JSON.toJavaObject(jsonObject, SystemBaseConfigVo.class);
        } catch (Exception exception) {
            throw new Blog4jException(ErrorEnum.PARSE_ERROR);
        }
    }

    private void addUserIllegalRecord(String userId, Integer illegalType) {
        UserIllegalRecordVo recordVo = UserIllegalRecordVo.builder()
                .userId(userId)
                .illegalType(illegalType)
                .createTime(CommonUtil.getCurrentDateTime())
                .build();
        userIllegalRecordService.addUserIllegalRecord(recordVo);
    }


}
